import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;

/**
 * 简单的 Tank Battle 示例（单文件）
 * 兼容 Java 8
 *
 * 控制：
 * 方向键 - 移动
 * 空格 - 发射子弹
 *
 * 说明：
 * FPS = frames per second（每秒帧数）
 */
public class TankGame extends JFrame {
    public TankGame() {
        setTitle("Tank Battle");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        GamePanel panel = new GamePanel();
        add(panel);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
        panel.startGame();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new TankGame());
    }
}

/* 游戏主面板 */
class GamePanel extends JPanel implements Runnable {
    static final int WIDTH = 800;
    static final int HEIGHT = 600;
    Thread gameThread;
    volatile boolean running = false;
    final int TARGET_FPS = 60; // frames per second（每秒帧数）
    Tank player;
    List<Tank> enemies = Collections.synchronizedList(new ArrayList<>());
    List<Bullet> bullets = Collections.synchronizedList(new ArrayList<>());
    List<Explosion> explosions = Collections.synchronizedList(new ArrayList<>());
    Random rand = new Random();

    public GamePanel() {
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(Color.DARK_GRAY);
        setFocusable(true);
        initGame();
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                player.keyPressed(e);
            }
            @Override
            public void keyReleased(KeyEvent e) {
                player.keyReleased(e);
            }
        });
    }

    void initGame() {
        player = new Tank(WIDTH/2 - 20, HEIGHT - 80, Direction.UP, true);
        // 创建若干敌方坦克
        for (int i = 0; i < 5; i++) {
            int x = 50 + i * 140;
            int y = 50 + rand.nextInt(80);
            Tank et = new Tank(x, y, Direction.DOWN, false);
            et.setSpeed(1 + rand.nextInt(2));
            et.setAutoFire(true);
            enemies.add(et);
        }
    }

    public void startGame() {
        running = true;
        gameThread = new Thread(this);
        gameThread.start();
    }

    public void stopGame() {
        running = false;
    }

    @Override
    public void run() {
        long lastTime = System.nanoTime();
        double nsPerFrame = 1e9 / TARGET_FPS;
        while (running) {
            long now = System.nanoTime();
            if (now - lastTime >= nsPerFrame) {
                updateGame();
                repaint();
                lastTime = now;
            } else {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException ignored) {}
            }
        }
    }

    void updateGame() {
        player.update();
        // 更新敌方
        synchronized (enemies) {
            for (Tank t : enemies) {
                t.autoMove(WIDTH, HEIGHT);
                if (t.isAutoFire() && rand.nextInt(100) < 2) {
                    bullets.add(t.fire());
                }
            }
        }
        // 更新子弹
        synchronized (bullets) {
            Iterator<Bullet> it = bullets.iterator();
            while (it.hasNext()) {
                Bullet b = it.next();
                b.update();
                if (!b.isAlive()) {
                    it.remove();
                    continue;
                }
                // 子弹碰撞检测：玩家子弹撞敌方，敌方子弹撞玩家（友军不伤害）
                if (b.isFromPlayer()) {
                    synchronized (enemies) {
                        Iterator<Tank> etIt = enemies.iterator();
                        while (etIt.hasNext()) {
                            Tank et = etIt.next();
                            if (et.isAlive() && et.getRect().intersects(b.getRect())) {
                                et.setAlive(false);
                                b.setAlive(false);
                                explosions.add(new Explosion(et.x, et.y));
                                etIt.remove();
                                break;
                            }
                        }
                    }
                } else {
                    if (player.isAlive() && player.getRect().intersects(b.getRect())) {
                        player.setAlive(false);
                        b.setAlive(false);
                        explosions.add(new Explosion(player.x, player.y));
                    }
                }
            }
        }
        // 敌方与玩家碰撞（简单处理：若相交，两者受损）
        synchronized (enemies) {
            for (Tank et : enemies) {
                if (player.isAlive() && et.isAlive() && player.getRect().intersects(et.getRect())) {
                    player.setAlive(false);
                    et.setAlive(false);
                    explosions.add(new Explosion(player.x, player.y));
                    explosions.add(new Explosion(et.x, et.y));
                }
            }
        }
        // 更新爆炸效果
        synchronized (explosions) {
            Iterator<Explosion> exIt = explosions.iterator();
            while (exIt.hasNext()) {
                Explosion ex = exIt.next();
                ex.update();
                if (!ex.isAlive()) exIt.remove();
            }
        }
        // 自动为移动中的坦克发射（玩家在按空格时发射）
        // 收集坦克发射的子弹（玩家发射）
        Bullet pb = player.pollFiredBullet();
        if (pb != null) bullets.add(pb);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 渲染地面网格（可选）
        Graphics2D g2 = (Graphics2D) g;
        // 渲染玩家/敌人/子弹/爆炸
        if (player.isAlive()) player.draw(g2);
        synchronized (enemies) {
            for (Tank t : enemies) t.draw(g2);
        }
        synchronized (bullets) {
            for (Bullet b : bullets) b.draw(g2);
        }
        synchronized (explosions) {
            for (Explosion ex : explosions) ex.draw(g2);
        }
        // HUD
        g2.setColor(Color.WHITE);
        g2.drawString("Enemies: " + enemies.size(), 10, 20);
        g2.drawString("Player: " + (player.isAlive() ? "Alive" : "Dead"), 10, 36);
        g2.drawString("Bullets: " + bullets.size(), 10, 52);
        if (!player.isAlive()) {
            g2.setFont(new Font("Arial", Font.BOLD, 36));
            g2.setColor(Color.YELLOW);
            g2.drawString("YOU DIED - Restart the program to play again", 80, HEIGHT/2);
        } else if (enemies.isEmpty()) {
            g2.setFont(new Font("Arial", Font.BOLD, 36));
            g2.setColor(Color.GREEN);
            g2.drawString("YOU WIN!", WIDTH/2 - 80, HEIGHT/2);
        }
    }
}

/* 坦克 */
class Tank {
    int x, y;
    int width = 40, height = 40;
    int speed = 2;
    Direction dir = Direction.UP;
    boolean isPlayer;
    boolean alive = true;
    boolean up, down, left, right;
    boolean firing = false;
    boolean autoFire = false;
    private Bullet firedBullet = null;
    Random rand = new Random();

    public Tank(int x, int y, Direction dir, boolean isPlayer) {
        this.x = x;
        this.y = y;
        this.dir = dir;
        this.isPlayer = isPlayer;
    }

    public void setSpeed(int s) { this.speed = s; }
    public boolean isAlive() { return alive; }
    public void setAlive(boolean a) { alive = a; }
    public Rectangle getRect() { return new Rectangle(x, y, width, height); }
    public boolean isAutoFire() { return autoFire; }
    public void setAutoFire(boolean b) { autoFire = b; }

    public void update() {
        if (!isPlayer) return;
        if (!alive) return;
        int dx = 0, dy = 0;
        if (up) { dy -= speed; dir = Direction.UP; }
        if (down) { dy += speed; dir = Direction.DOWN; }
        if (left) { dx -= speed; dir = Direction.LEFT; }
        if (right) { dx += speed; dir = Direction.RIGHT; }
        x += dx; y += dy;
        boundWithin(0,0, GamePanel.WIDTH, GamePanel.HEIGHT);
        if (firing) {
            tryFire();
        }
    }

    // 敌方简单自动移动
    public void autoMove(int areaW, int areaH) {
        if (!alive) return;
        if (isPlayer) return;
        // 随机改变方向
        if (rand.nextInt(100) < 3) {
            dir = Direction.values()[rand.nextInt(Direction.values().length)];
        }
        int dx = 0, dy = 0;
        switch (dir) {
            case UP: dy = -speed; break;
            case DOWN: dy = speed; break;
            case LEFT: dx = -speed; break;
            case RIGHT: dx = speed; break;
        }
        x += dx; y += dy;
        // 边界处理
        if (x < 0) x = 0;
        if (y < 0) y = 0;
        if (x > areaW - width) x = areaW - width;
        if (y > areaH - height) y = areaH - height;
        // 偶尔开火
        if (rand.nextInt(100) < 2) {
            firedBullet = createBullet(false);
        } else {
            firedBullet = null;
        }
    }

    public Bullet pollFiredBullet() {
        Bullet b = firedBullet;
        firedBullet = null;
        return b;
    }

    private void boundWithin(int minX, int minY, int maxX, int maxY) {
        if (x < minX) x = minX;
        if (y < minY) y = minY;
        if (x > maxX - width) x = maxX - width;
        if (y > maxY - height) y = maxY - height;
    }

    public void draw(Graphics2D g) {
        if (!alive) return;
        // 画坦克底盘
        g.setColor(isPlayer ? Color.CYAN : Color.RED);
        g.fillRect(x, y, width, height);
        // 画炮管
        g.setColor(Color.BLACK);
        int cx = x + width/2;
        int cy = y + height/2;
        int len = 30;
        switch (dir) {
            case UP: g.fillRect(cx - 4, y - len/2 + 8, 8, len); break;
            case DOWN: g.fillRect(cx - 4, y + height - 8, 8, len); break;
            case LEFT: g.fillRect(x - len/2 + 8, cy - 4, len, 8); break;
            case RIGHT: g.fillRect(x + width - 8, cy - 4, len, 8); break;
        }
    }

    public Bullet fire() {
        return createBullet(isPlayer);
    }

    private void tryFire() {
        if (!alive) return;
        if (firedBullet == null) {
            firedBullet = createBullet(true);
        }
    }

    private Bullet createBullet(boolean fromPlayer) {
        int bx = x + width/2 - 4;
        int by = y + height/2 - 4;
        return new Bullet(bx, by, dir, fromPlayer);
    }

    // 控制输入
    public void keyPressed(KeyEvent e) {
        if (!isPlayer) return;
        int code = e.getKeyCode();
        if (code == KeyEvent.VK_UP) up = true;
        if (code == KeyEvent.VK_DOWN) down = true;
        if (code == KeyEvent.VK_LEFT) left = true;
        if (code == KeyEvent.VK_RIGHT) right = true;
        if (code == KeyEvent.VK_SPACE) firing = true;
    }
    public void keyReleased(KeyEvent e) {
        if (!isPlayer) return;
        int code = e.getKeyCode();
        if (code == KeyEvent.VK_UP) up = false;
        if (code == KeyEvent.VK_DOWN) down = false;
        if (code == KeyEvent.VK_LEFT) left = false;
        if (code == KeyEvent.VK_RIGHT) right = false;
        if (code == KeyEvent.VK_SPACE) firing = false;
    }
}

/* 子弹 */
class Bullet {
    int x, y;
    int size = 8;
    int speed = 6;
    Direction dir;
    boolean alive = true;
    boolean fromPlayer;

    public Bullet(int x, int y, Direction dir, boolean fromPlayer) {
        this.x = x;
        this.y = y;
        this.dir = dir;
        this.fromPlayer = fromPlayer;
    }

    public void update() {
        switch (dir) {
            case UP: y -= speed; break;
            case DOWN: y += speed; break;
            case LEFT: x -= speed; break;
            case RIGHT: x += speed; break;
        }
        if (x < 0 || y < 0 || x > GamePanel.WIDTH || y > GamePanel.HEIGHT) alive = false;
    }

    public void draw(Graphics2D g) {
        if (!alive) return;
        g.setColor(fromPlayer ? Color.YELLOW : Color.ORANGE);
        g.fillOval(x, y, size, size);
    }

    public Rectangle getRect() { return new Rectangle(x, y, size, size); }
    public boolean isAlive() { return alive; }
    public void setAlive(boolean a) { alive = a; }
    public boolean isFromPlayer() { return fromPlayer; }
}

/* 爆炸效果 */
class Explosion {
    int x, y;
    int life = 30;
    int age = 0;
    public Explosion(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void update() { age++; }
    public boolean isAlive() { return age < life; }
    public void draw(Graphics2D g) {
        int r = age * 3;
        float alpha = 1.0f - (float)age / life;
        Composite old = g.getComposite();
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, Math.max(0f, alpha)));
        g.setColor(Color.ORANGE);
        g.fillOval(x - r/2, y - r/2, r, r);
        g.setComposite(old);
    }
}

enum Direction { UP, DOWN, LEFT, RIGHT }
